package org.fund.base_service.service.impl;


import org.fund.base_service.domain.Position;
import org.fund.base_service.domain.TransactionRecord;
import org.fund.base_service.domain.UserPositonRelation;
import org.fund.base_service.domain.vo.PositionVO;
import org.fund.base_service.domain.vo.TransactionRecordVO;
import org.fund.base_service.mapper.PositionMapper;
import org.fund.base_service.mapper.TransactionRecordMapper;
import org.fund.base_service.service.PositionService;
import org.fund.base_service.service.TransactionRecordService;
import org.fund.base_service.service.UserPositonRelationService;
import org.fund.common.constant.ErrorCode;
import org.fund.common.constant.FundEnum;
import org.fund.common.constant.OperatorCurrentStatus;
import org.fund.common.exception.ServiceException;
import org.fund.common.model.FundEstimate;
import org.fund.common.model.FundValue;
import org.fund.common.util.BigDecimalUtils;
import org.fund.common.util.DateUtils;
import org.fund.common.util.SecurityUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 持仓(Position)表服务实现类
 *
 * @author makejava
 * @since 2022-03-13 01:28:43
 */
@Service
public class PositionServiceImpl implements PositionService {
    @Autowired
    private PositionMapper positionMapper;

    public static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    @Autowired
    private FundService fundService;
    @Autowired
    private UserPositonRelationService userPositonRelationService;
    @Autowired
    private TransactionRecordMapper recordMapper;
    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public PositionVO queryById(Integer id) {
        Position position = this.positionMapper.queryById(id);
        FundEstimate jzEstimate = fundService.getJZEstimate(position.getFundCode());
        PositionVO vo = new PositionVO();
        BeanUtils.copyProperties(position,vo);
        vo.setType(FundEnum.getInstance(position.getFundType()));
        vo.setFundEstimate(jzEstimate);
        return vo;
    }

    /**
     *  查询所有持仓数据
     * @return 查询结果
     */
    @Override
    public List<PositionVO> queryAll() {
        List<Position> positions = positionMapper.queryAll(SecurityUtils.getUserId());
        if (CollectionUtils.isEmpty(positions)) {
            return Collections.emptyList();
        }
        List<PositionVO> vos  = new ArrayList<>(positions.size());
        for (Position p : positions) {
            FundEstimate jzEstimate = fundService.getJZEstimate(p.getFundCode());
            PositionVO vo = new PositionVO();
            BeanUtils.copyProperties(p,vo);
            vo.setType(FundEnum.getInstance(p.getFundType()));
            vo.setFundEstimate(jzEstimate);
            vos.add(vo);
        }
        return vos;
    }

    /**
     * 新增持仓
     *
     * @param position 实例对象
     */
    @Transactional
    @Override
    public void addPosition(Position position) {
        Position select = positionMapper.selectBySelective(position, SecurityUtils.getUserId().intValue());
        if (!Objects.isNull(select)){
            throw  new ServiceException(ErrorCode.FUND_IS_EXISTS);
        }
        int rows = positionMapper.insert(position);
        if (rows==1) {
            UserPositonRelation relation = new UserPositonRelation();
            relation.setPId(position.getId());
            relation.setUId(SecurityUtils.getUserId().intValue());
            userPositonRelationService.insert(relation);
        }else{
            throw new ServiceException(ErrorCode.SERVER_ERROR);
        }

    }

    /**
     * 修改数据
     *
     * @param position 实例对象
     */
    @Override
    public void update(Position position) {
        this.positionMapper.update(position);
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(Integer id) {
        return this.positionMapper.deleteById(id) > 0;
    }
    @Transactional
    @Override
    public void quickAdd(Position position) {
        Position select = positionMapper.selectBySelective(position, SecurityUtils.getUserId().intValue());
        if (!Objects.isNull(select)){
            throw  new ServiceException(ErrorCode.FUND_EXISTS);
        }
        BigDecimal holdTotal = position.getHoldPerPrice().divide(position.getHoldAmount()).setScale(4, BigDecimal.ROUND_UP);
        position.setHoldTotal(holdTotal);
        int row = positionMapper.insert(position);
        if (row==1){
            UserPositonRelation relation = new UserPositonRelation();
            relation.setPId(position.getId());
            relation.setUId(SecurityUtils.getUserId().intValue());
            userPositonRelationService.insert(relation);
        }
    }
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void purchase(TransactionRecordVO record) throws ParseException {
        boolean isBefore = DateUtils.dayBefore(record.getOperatorTime());
        Position p  = positionMapper.queryById(record.getPId());
        if (isBefore) {
            // 判断买入日期是否在当前时间的前一天
            record.setCurrentStatus(OperatorCurrentStatus.PURCHASE_CONFIRMED.getCode());
            //计算确认当日价格
            BigDecimal confirmPrice = geConfirmPrice(record);
            record.setConfirmPrice(confirmPrice);
            // 计算花费
            BigDecimal cost = new BigDecimal(record.getAmount()).multiply(record.getRate()).setScale(4, BigDecimal.ROUND_HALF_UP);
            record.setCost(cost);
            //计算确认份额
            BigDecimal confirmAmount = new BigDecimal(record.getAmount()).divide(confirmPrice,4,BigDecimal.ROUND_HALF_UP);
            record.setConfirmAmount(confirmAmount);
            //当前持有份额
            BigDecimal holdAmount = p.getHoldAmount();
            // 当前本金
            BigDecimal holdTotal = p.getHoldTotal();
            // 新的本金
            BigDecimal newHoldTotal = holdTotal.add(new BigDecimal(record.getAmount()));
            p.setHoldTotal(newHoldTotal);
            // 新的持有份额
            BigDecimal newHoldAmount = holdAmount.add(confirmAmount);
            p.setHoldAmount(newHoldAmount);
            // 新的成本价
            BigDecimal newHoldPerPrice = newHoldTotal.divide(newHoldAmount,4, BigDecimal.ROUND_HALF_UP);
            p.setHoldPerPrice(newHoldPerPrice);
            positionMapper.update(p);
        }else {
            record.setCurrentStatus(OperatorCurrentStatus.PURCHASE_TO_CONFIRMED.getCode());
        }
        TransactionRecord re = new TransactionRecord();
        BeanUtils.copyProperties(record, re);
        re.setUId(SecurityUtils.getUserId());
        recordMapper.insert(re);
    }

    @Override
    public void sale(TransactionRecordVO record) {
        Position p  = positionMapper.queryById(record.getPId());
        if (new BigDecimal(record.getAmount()).compareTo(p.getHoldAmount()) > 0){
            throw new ServiceException(ErrorCode.SALE_AMOUNT_MORE_THAN_HOLD_AMOUNT);
        }
        // 判断买入日期是否在当前时间的前一天
        record.setCurrentStatus(OperatorCurrentStatus.SALE_CONFIRMED.getCode());
        //计算确认当日价格
        BigDecimal confirmPrice = geConfirmPrice(record);
        //计算确认份额
        BigDecimal confirmAmount = new BigDecimal(record.getAmount());
        record.setConfirmAmount(confirmAmount);
        record.setConfirmPrice(BigDecimalUtils.to4Decimal(confirmPrice));
        //当前持有份额
        BigDecimal holdAmount = p.getHoldAmount();
        // 当前本金
        BigDecimal holdTotal = p.getHoldTotal();
        //卖出的钱
        BigDecimal saleAmount = BigDecimalUtils.to4Decimal(confirmAmount.multiply(confirmPrice));
        // 新的本金
        BigDecimal newHoldTotal = BigDecimalUtils.to4Decimal(holdTotal.subtract(saleAmount));
        p.setHoldTotal(newHoldTotal);
        // 新的持有份额
        BigDecimal newHoldAmount = BigDecimalUtils.to4Decimal(holdAmount.subtract(confirmAmount));
        p.setHoldAmount(newHoldAmount);
        // 新的成本价
        BigDecimal newHoldPerPrice =newHoldTotal.divide(newHoldAmount,4,BigDecimal.ROUND_HALF_UP);
        p.setHoldPerPrice(newHoldPerPrice);
        positionMapper.update(p);
        TransactionRecord re = new TransactionRecord();
        BeanUtils.copyProperties(record, re);
        re.setUId(SecurityUtils.getUserId());
        recordMapper.insert(re);
    }

    /**
     * 计算确认当日价格
     * @param record
     * @return
     */
    private BigDecimal geConfirmPrice(TransactionRecordVO record) {
        // 如果是周末或者是节假日 计算之前的最后一个工作日
        String workDay = DateUtils.getWorkDay(record.getOperatorTime());
        long nextDay = record.getOperatorTime().getTime() + 1000 * 60 * 60 * 24;
        Date date = new Date(nextDay);
        List<FundValue> lsjz = fundService.lsjz(record.getFundCode(), 1, workDay, sdf.format(date));
        FundValue fundValue = lsjz.get(0);
        // 计算确认价格
        return new BigDecimal(fundValue.getDWJZ());
    }

    @Override
    public void revoke(TransactionRecordVO record) {

    }
//    @Async("executor")
//    public void calculatePosition(TransactionRecord record){
//
//    }
}
